﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CRMAdminDashboard.CrmSvc;
using System.Collections;
using System.Xml.Serialization;
using System.IO;
using System.Net;

namespace CRMAdminDashboard
{

    /// <summary>
    /// Caching layer over CrmService
    /// </summary>
    public class CachingCrmService
    {

        [Serializable]
        public class RetrieveRequest
        {
            public string EntityName { get; set; }
            public Guid Id { get; set; }
            public ColumnSetBase ColumnSet { get; set; }
        }

        #region Properties

        public ICredentials Credentials
        {
            get
            {
                return _svcHandle.Credentials;
            }
            set
            {
                _svcHandle.Credentials = value;
            }
        }

        public CrmAuthenticationToken CrmAuthenticationTokenValue
        {
            get
            {
                return _svcHandle.CrmAuthenticationTokenValue;
            }
            set
            {
                _svcHandle.CrmAuthenticationTokenValue = value;
            }
        }

        public string Url
        {
            get
            {
                return _svcHandle.Url;
            }
            set
            {
                _svcHandle.Url = value;
            }
        }

        #endregion

        #region Fields

        private Hashtable _cache = new Hashtable();
        private XmlSerializer _serializerQueryBase = new XmlSerializer(typeof(QueryBase));
        private XmlSerializer _serializerBusinessEntityCollection = new XmlSerializer(typeof(BusinessEntityCollection));
        private XmlSerializer _serializerRetrieveRequest = new XmlSerializer(typeof(RetrieveRequest));
        private XmlSerializer _serializerBusinessEntity = new XmlSerializer(typeof(BusinessEntity));
        private XmlSerializer _serializerRequest = new XmlSerializer(typeof(Request));
        private XmlSerializer _serializerResponse = new XmlSerializer(typeof(Response));
        private CrmService _svcHandle = new CrmService();

        #endregion

        #region Entry Points

        public void InvalidateCache()
        {
            this._cache.Clear();
        }

        public Response Execute(Request request)
        {
            using (StringWriter writer1 = new StringWriter())
            {
                _serializerRequest.Serialize(writer1, request);
                string key = writer1.ToString();
                if (_cache.ContainsKey(key))
                {
                    using (StringReader reader = new StringReader((string)_cache[key]))
                    {
                        return (Response)_serializerResponse.Deserialize(reader);
                    }
                }
                else
                {
                    Response ret = _svcHandle.Execute(request);
                    using (StringWriter writer2 = new StringWriter())
                    {
                        _serializerResponse.Serialize(writer2, ret);
                        _cache[key] = writer2.ToString();
                        return ret;
                    }
                }
            }
        }

        public BusinessEntityCollection RetrieveMultiple(QueryBase query)
        {
            using (StringWriter writer1 = new StringWriter())
            {
                _serializerQueryBase.Serialize(writer1, query);
                string key = writer1.ToString();
                if (_cache.ContainsKey(key))
                {
                    using (StringReader reader = new StringReader((string)_cache[key]))
                    {
                        return (BusinessEntityCollection)_serializerBusinessEntityCollection.Deserialize(reader);
                    }
                }
                else
                {
                    BusinessEntityCollection ret = _svcHandle.RetrieveMultiple(query);
                    using (StringWriter writer2 = new StringWriter())
                    {
                        _serializerBusinessEntityCollection.Serialize(writer2, ret);
                        _cache[key] = writer2.ToString();
                        return ret;
                    }
                }
            }
        }

        public BusinessEntity Retrieve(string entityName, Guid id, ColumnSetBase columnSet)
        {
            RetrieveRequest request = new RetrieveRequest();
            request.EntityName = entityName;
            request.Id = id;
            request.ColumnSet = columnSet;
            using (StringWriter writer1 = new StringWriter())
            {
                _serializerRetrieveRequest.Serialize(writer1, request);
                string key = writer1.ToString();
                if (_cache.ContainsKey(key))
                {
                    using (StringReader reader = new StringReader((string)_cache[key]))
                    {
                        return (BusinessEntity)_serializerBusinessEntity.Deserialize(reader);
                    }
                }
                else
                {
                    BusinessEntity ret = _svcHandle.Retrieve(entityName, id, columnSet);
                    using (StringWriter writer2 = new StringWriter())
                    {
                        _serializerBusinessEntity.Serialize(writer2, ret);
                        _cache[key] = writer2.ToString();
                        return ret;
                    }
                }
            }
        }

        public BusinessEntity RetrieveNoCache(string entityName, Guid id, ColumnSetBase columnSet)
        {
            RetrieveRequest request = new RetrieveRequest();
            request.EntityName = entityName;
            request.Id = id;
            request.ColumnSet = columnSet;
            using (StringWriter writer1 = new StringWriter())
            {
                _serializerRetrieveRequest.Serialize(writer1, request);
                string key = writer1.ToString();
                BusinessEntity ret = _svcHandle.Retrieve(entityName, id, columnSet);
                using (StringWriter writer2 = new StringWriter())
                {
                    _serializerBusinessEntity.Serialize(writer2, ret);
                    _cache[key] = writer2.ToString();
                    return ret;
                }
            }
        }

        public Guid Create(BusinessEntity entity)
        {
            return _svcHandle.Create(entity);
        }

        public void Update(BusinessEntity entity)
        {
            _svcHandle.Update(entity);
        }

        public void Delete(string entityName, System.Guid id)
        {
            _svcHandle.Delete(entityName, id);
        }

        #endregion

    }
}
